﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Dynamic;
using System.IO;
using System.Text.RegularExpressions;
using System.Reflection;
using System.Globalization;

namespace Red
{


    public class RedObject: DynamicObject
    {
        Dictionary<string, object> dictionary = new Dictionary<string, object>();

        public int Count { get { return dictionary.Count; } }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            return dictionary.TryGetValue(binder.Name, out result);
        }

        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            dictionary[binder.Name] = value;
            return true;
        }

        public override IEnumerable<string> GetDynamicMemberNames()
        {
            return dictionary.Keys;
        }

        RedObject()
        {

        }
        RedObject _Parent;
        int _Indent;
        bool _IsInArray;
        string _LastMember;
        //public dynamic RootObject = new ExpandoObject();
        public RedObject(Stream stream)
        {
            var sr = new StreamReader(stream);
            int ln = 0;
            var str = sr.ReadLine();
            var current = this;
            current._Parent = null;
            current._Indent = 0;
            current._IsInArray = false;
            var ttt = current._Parent;
            while (str != null)
            {
                var match = reg.Match(str);
                if (!match.Success)
                {
                    match = reg2.Match(str);
                    if (!match.Success)
                        throw new Exception(str);
                }
                var indent = (int)Math.Ceiling(match.Groups["spaces"].Value.Length / 4.0);
                var name = match.Groups["name"].Value;
                if (name == "object" || name == "operator")
                {
                    name += '_';
                }
                var value = match.Groups["value"].Value.Trim();
                var min = !string.IsNullOrEmpty(match.Groups["min"].Value);
                if (value.StartsWith("[") && !value.EndsWith("]"))
                {
                    ln++;
                    str = sr.ReadLine();
                    value += " " + str.Trim();
                    while (!str.EndsWith("]"))
                    {
                        ln++;
                        str = sr.ReadLine();
                        value += " " + str.Trim();
                    }
                }
                if (value.StartsWith("\"") && !value.EndsWith("\""))
                {
                    ln++;
                    str = sr.ReadLine();
                    value += " " + str.Trim();
                    while (!str.EndsWith("\""))
                    {
                        ln++;
                        str = sr.ReadLine();
                        value += " " + str.Trim();
                    }
                }
                var oldIndent = current._Indent;
                if (indent > oldIndent)
                {
                    RedObject newOne = new RedObject();
                    newOne._Parent = current;
                    newOne._Indent = indent;
                    newOne._IsInArray = false;
                    if (min)
                    {
                        newOne._IsInArray = true;
                        var last1 = new List<dynamic>();
                        current.dictionary[current._LastMember] = last1;
                        last1.Add(newOne);
                        if (!name.StartsWith("*") && !name.StartsWith("&"))
                        {
                            newOne.dictionary[name] = value;
                            newOne._LastMember = name;
                        }
                        current = newOne;
                    }
                    else if (!name.StartsWith("*") && !name.StartsWith("&"))
                    {

                        current.dictionary[current._LastMember] = newOne;
                        if (value == "[]")
                            newOne.dictionary[name] = new List<dynamic>();
                        else
                            newOne.dictionary[name] = value;
                        current = newOne;
                        current._LastMember = name;
                    }
                }
                else if (indent == oldIndent)
                {
                    if (!min)
                    {
                        if (value == "[]")
                            current.dictionary[name] = new List<dynamic>();
                        else
                            current.dictionary[name] = value;
                        current._LastMember = name;
                    }
                    else
                    {
                        var arrpar = current;
                        if (current._IsInArray)
                            arrpar = current._Parent;
                        RedObject newOne = new RedObject();
                        newOne._Parent = arrpar;
                        newOne._Indent = indent;
                        newOne._IsInArray = true;
                        var last = arrpar.dictionary[arrpar._LastMember];
                        ((List<dynamic>)last).Add(newOne);
                        if (value == "[]")
                            newOne.dictionary[name] = new List<dynamic>();
                        else
                            newOne.dictionary[name] = value;
                        current = newOne;
                        current._LastMember = name;
                    }

                }
                else if (indent < oldIndent)
                {
                    for (int i = indent; i < oldIndent; i++)
                    {
                        current = current._Parent;
                    }
                    if (min)
                    {
                        RedObject newOne = new RedObject();
                        newOne._Indent = indent;
                        newOne._IsInArray = true;
                        var arrpar = current;
                        if (current._IsInArray && current._Indent == indent)
                            arrpar = current._Parent;
                        newOne._Parent = arrpar;
                        var last = arrpar.dictionary[arrpar._LastMember] as List<dynamic>;
                        if (last != null)
                        {
                            last.Add(newOne);
                        }
                        else
                        {
                            var last1 = new List<dynamic>();
                            arrpar.dictionary[arrpar._LastMember] = last1;
                            last1.Add(newOne);
                        }
                        if (!name.StartsWith("*") && !name.StartsWith("&"))
                        {
                            if (value == "[]")
                                newOne.dictionary[name] = new List<dynamic>();
                            else
                                newOne.dictionary[name] = value;
                            newOne._LastMember = name;
                        }
                        current = newOne;
                    }
                    else if (!name.StartsWith("*") && !name.StartsWith("&"))
                    {
                        if (value == "[]")
                            current.dictionary[name] = new List<dynamic>();
                        else
                            current.dictionary[name] = value;
                        current._LastMember = name;
                    }
                }
                ln++;
                str = sr.ReadLine();
            }
        }

        public static Regex reg = new Regex(@"(?<spaces>\s*(?<min>-*)\s*)(?<name>[^:]+):\s*(?<value>.*)", RegexOptions.Compiled);
        public static Regex reg2 = new Regex(@"(?<spaces>\s*(?<min>-*)\s*)(?<name>.*)", RegexOptions.Compiled);
    }
}
